﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.ComponentModel;

namespace CoD4_Helper
{
    /// <summary>
    /// Represents a Config file
    /// </summary>
    sealed class ConfigFile
    {
        /// <summary>
        /// Provides methods for editing and customizing CFGs
        /// </summary>
        /// <param name="path">The path of the Config file</param>
        public ConfigFile(string path)
        {
            this.cfgPath = path;            
        }

        private string cfgPath;
        /// <summary>
        /// The path of the config
        /// </summary>
        public string CfgPath
        {
            get { return this.cfgPath; }
            private set
            {
                this.cfgPath = value;
            }
        }

        private BindingList<Utils.CfgCommand> cmds;

        public BindingList<Utils.CfgCommand> Commands
        {
            get { return this.cmds; }
            set { this.cmds = value; }
        }
        

        #region Custom Events
        public delegate void NewConfigEventHandler(object sender, EventArgs e);
        public event NewConfigEventHandler OnLoad;

        private void RaiseOnLoad()
        {
            if (this.OnLoad != null)
            {
                this.OnLoad(this, EventArgs.Empty);
            }
        }
        #endregion

        /// <summary>
        /// Get the size in KB of the Config file
        /// </summary>
        public string GetSize()
        {
            FileInfo fInfo = new FileInfo(this.cfgPath);
            return (fInfo.Length / 1024) + "KB";
        }

        /// <summary>
        /// Get the number of lines of the Config file
        /// </summary>
        public int GetNumOfLines()
        {
            return File.ReadLines(this.cfgPath).Count();
        }

        /// <summary>
        /// Load the Config file in to memory, so it's ready to be modified
        /// </summary>
        public void Load()
        {
            // TODO finish this!

            cmds = new BindingList<Utils.CfgCommand>();

            if (File.Exists(this.cfgPath))
            {
                // List to store each line of our cfg
                List<string> cfgLines = new List<string>();

                // opens the cfg
                using (StreamReader sr = new StreamReader(this.cfgPath))
                {
                    while (sr.EndOfStream == false)
                        cfgLines.Add(sr.ReadLine()); //copy every line to the list
                }

                // populate the Bindinglist where all the commands are stored
                foreach (var line in cfgLines)
                {
                    if (!(line.StartsWith("/") || line.Equals("unbindall"))) // means it's not a comment
                    {
                        // could be bind or seta, ex
                        // bind {key} {"value"}
                        // seta {codCmd} {"value"}
                        string cmdType = line.Substring(0, 4).ToLower();

                        switch (cmdType)
                        {
                            case "bind":
                            case "seta":
                                if (line.Contains('"')) // if contains quotes
                                {
                                    // index of first quote
                                    int index = line.IndexOf('"');
                                    // the value of the command
                                    string value = line.Substring(index);
                                    value = value.Substring(1, value.Length - 2); // remove quotes

                                    string fisrtPart = line.Substring(0, index - 1);

                                    string[] cmdTypeAndKey = fisrtPart.Split(' ');

                                    string key = cmdTypeAndKey[1];

                                    this.cmds.Add(new Utils.CfgCommand(key, value, cmdType));
                                }
                                break;
                            default:
                                this.cmds.Add(new Utils.CfgCommand(line, null, null));
                                break;
                        } // switch
                    }

                } // foreach line

                // Rise the event
                RaiseOnLoad();
            }
            
        }

        /// <summary>
        /// Writes the changes made to the opened ConfigFile
        /// </summary>
        public void Save()
        {
            this.Save(null);
        }

        /// <summary>
        /// Save the config file in a user defined path
        /// </summary>
        /// <param name="newPath">The path were you want to save the config file</param>
        public void Save(string newPath)
        {
            if (newPath != null)
            {
                using (StreamWriter sw = new StreamWriter(newPath))
                {
                    sw.WriteLine("// generated by Call of Duty, do not modify");
                    sw.WriteLine("unbindall");

                    foreach (var item in this.cmds)
                    {
                        switch (item.Type)
                        {
                            case "bind": sw.WriteLine("bind " + item.Command + " \"" + item.Value + "\"");
                                break;
                            case "seta": sw.WriteLine("seta " + item.Command + " \"" + item.Value + "\"");
                                break;
                            default: sw.WriteLine(item.Command);
                                break;
                        }

                    }
                }
            }
        }


        /// <summary>
        /// Gets a list of commands and binds from the Config file
        /// </summary>
        /// <returns></returns>
        public List<Utils.CfgCommand> old_GetCmds()
        {
            //// List to store each line of our cfg
            List<string> lines = new List<string>();

            // stores commands/binds 
            List<Utils.CfgCommand> cmds = new List<Utils.CfgCommand>();

            // open the cfg
            using (StreamReader sr = new StreamReader(this.cfgPath))
            {
                while (sr.EndOfStream == false)
                    lines.Add(sr.ReadLine()); //copy evry line to the list
            }

            // perform operations
            foreach (var line in lines)
            {
                if (!(line.StartsWith("/") || line.Equals("unbindall"))) // means it's not a comment
                {
                    // could be bind or seta, ex
                    // bind {key} {"value"}
                    // seta {codCmd} {"value"}
                    string cmdType = line.Substring(0, 4).ToLower();

                    switch (cmdType)
                    {
                        case "bind":
                        case "seta":
                            if (line.Contains('"')) // if contains quotes
                            {
                                // index of first quote
                                int index = line.IndexOf('"');
                                // the value of the command
                                string value = line.Substring(index);
                                value = value.Substring(1, value.Length - 2); // remove quotes

                                string fisrtPart = line.Substring(0, index - 1);

                                string[] cmdTypeAndKey = fisrtPart.Split(' ');

                                string key = cmdTypeAndKey[1];

                                cmds.Add(new Utils.CfgCommand(key, value, cmdType));
                            }
                            break;
                        default:
                            cmds.Add(new Utils.CfgCommand(line, null, null));
                            break;
                    } // switch
                }
                
            } // foreach line

            return cmds;        

        } // GetCmds end


    }
}
